'use strict';

const Service = require('egg').Service;

class PriceService extends Service {
  // trx默认地址转换16进制
  async addressToHex(address) {
    const { app } = this;
    return await app.BSC.Web3.address.toHex(address);
  }

  // 16进制地址转换成trx默认地址
  async addressFromHex(address) {
    const { app } = this;
    return await app.BSC.Web3.address.fromHex(address);
  }

  // trx默认地址转换16进制, 并且0x开头
  async addressToHex2(address) {
    const { app } = this;
    if (address.indexOf('0x') === 0) {
      return address;
    }
    address = await app.BSC.Web3.address.toHex(address);
    return address.replace('41', '0x');
  }

  // 创建合约对象
  async createdContract(abi, address) {
    const { app } = this;
    return await app.BSC.Web3.contract(abi, address);
  }

  // 创建一个erc20合约对象
  async createdContractERC20(_tokenAddress) {
    const { app } = this;
    const ERC20Abi = app.Init.erc20Abi;
    return await app.BSC.Web3.contract(ERC20Abi, _tokenAddress);
  }

  // 传入合约地址, 查询用户地址的余额, 并且除以精度;--
  async getErc20BalanceAll(_tokenAddress, _userAddress) {
    const { app, ctx } = this;
    const contractObj = await this.createdContractERC20(_tokenAddress);
    // 计算除去的小数位
    let numberZero = await contractObj.methods.decimals().call();
    numberZero = ctx.helper.pow('10', numberZero);
    let res = await contractObj.methods.balanceOf(_userAddress).call();
    return ctx.helper.div(ctx.helper.scientificNotationToString(ctx.helper.hexToDec(res.balance._hex)), numberZero);
  }

  // 根据地址获取配对地址, 不存在返回trx默认的0地址;
  async getExchange2(_tokenAddress) {
    const { app, ctx } = this;
    const factoryContract = app.Init.factoryContract;
    const res = await factoryContract.methods.getExchange(_tokenAddress).call();
    return this.addressFromHex(res);
  }

  // 获取余额TRX
  async getTrxBlance(address) {
    const { app, ctx } = this;
    const res = await app.BSC.Web3.trx.getBalance(address);
    return ctx.helper.div(res, app.Init.zero6);
  }

  // 根据配对地址获取代币地址, 不存在返回trx默认的0地址;
  async getToken2(_exchangeAddress) {
    const { app, ctx } = this;
    const factoryContract = app.Init.factoryContract;
    const res = await factoryContract.methods.getToken(_exchangeAddress).call();
    return this.addressFromHex(res);
  }

  // 获取代币的价格; 1个代币=>N个trx;
  // 参数1: 代币的配对合约地址,
  async getTokenToTrx2(_pairAddress) {
    const { app, ctx } = this;
    const tokenAddress = await this.getToken2(_pairAddress);
    let balanceTrx = await this.getTrxBlance(_pairAddress);
    let tokenTrx = await this.getErc20BalanceAll(tokenAddress, _pairAddress);
    return ctx.helper.div(balanceTrx, tokenTrx);
  }

  // 获取trx的价格(USDT); 1个trx->N个usdt
  async trxToUsdt2() {
    const { app, ctx } = this;
    const _pairAddress = 'TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE';
    const tokenAddress = await this.getToken2(_pairAddress);
    let balanceTrx = await this.getTrxBlance(_pairAddress);
    let tokenTrx = await this.getErc20BalanceAll(tokenAddress, _pairAddress);
    return ctx.helper.div(tokenTrx, balanceTrx);
  }

  // 封装; 传入token地址, 返回USDT价格; 1个token=>N个USDT
  // 如果没有价格, 默认返回1;
  // 参数1: token地址
  async getTokenToUsdtPrice(_tokenAddress) {
    const { app, ctx } = this;
    const _pairAddress = await this.getExchange2(_tokenAddress);
    if(_pairAddress === app.Init.zeroAddress2) {
      return '1';
    }
    let res1 = await this.getTokenToTrx2(_pairAddress);
    let res2 = await this.trxToUsdt2();
    return ctx.helper.mul(res1, res2);
  }

  //// 获取某个token的价格; 单位是usdt
  // 参数1: token的地址
  async getTokenPrice2(_tokenAddress) {
    const { app } = this;
    // 如果是usdt地址就直接返回1
    const usdtAddress = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t';
    if (_tokenAddress === usdtAddress) {
      return '1';
    }
    return await this.getTokenToUsdtPrice(_tokenAddress);
  }

  //// 获取某个lp价格; 单位是usdt
  // 参数1: lp地址
  async getLpPrice2(_lpAddress) {
    const { app, ctx } = this;
    const token0Address = await this.getToken2(_lpAddress);
    if (token0Address === app.Init.zeroAddress2) {
      // 没有配对合约就默认价格是1
      return '1';
    }

    const pairAbi = app.Init.pairAbi;
    const ERC20Abi = app.Init.erc20Abi;
    const token0Contract = await this.createdContract(ERC20Abi, token0Address);
    const pairContract = await this.createdContract(pairAbi, _lpAddress);

    // 获取总量
    const token0Reserve = await this.getErc20BalanceAll(token0Address, _lpAddress);
    const token1Reserve = await this.getTrxBlance(_lpAddress);
    let lpSupply = await pairContract.methods.totalSupply().call({ _isConstant: true });
    lpSupply = ctx.helper.hexToDec(lpSupply._hex);
    lpSupply = ctx.helper.div(lpSupply, app.Init.zero6);
    // 获取价格
    const token0Price = await this.getTokenPrice2(token0Address);
    const token1Price = await this.trxToUsdt2();

    console.log('LP价格数据-LP对配对合约的token0总量,trx总量,token0价格,trx价格,LP总量:', token0Reserve, token1Reserve, token0Price, token1Price, lpSupply);
    // (token0Reserve * token0Price + token1Reserve * token0Price ) / lpSupply;
    const r1 = ctx.helper.mul(token0Reserve, token0Price);
    const r2 = ctx.helper.mul(token1Reserve, token1Price);
    const r3 = ctx.helper.add(r1, r2);
    return ctx.helper.div(r3, lpSupply);
  }


}

module.exports = PriceService;
